/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 * */

// AmzServer - Tototoy's server model.
// Author: tonyjobmails@gmail.com (tonyhack).
//
// Define class RingQueueSingleModelBound.
//
// RingQueueSingleModelBound is an implement of RingQueueInterface, This version
// is "double-thread safe". That is to say, there are only 2 threads in the producer/co
// -nsumer modle, the producer one only read from the queue, and the consumer one
// only write to it, RingQueueSingleModelBound is thread-safe in the condition.Because
// of using lock-free, this performances a high efficiency in this model.
// This RingQueueSingleModelBound uses a bound length buffer, it uses ByteBufferSt
// -aticMalloc as its buffer, it is a static buffer. So, when the buffer is full, the producer
// can not write any data until the consumer digest one or more data elements.
// RingQueueSingleModelBound supports blocking/non-blocking pattern. blocking is that
// when empty, the consumer will be block until any data is written into the queue, so
// does the condition of the queue being full. non-blocking is that any condition will not
// block producer or consumer thread, if empty/full, consumer/producer will return 0
// value to notify queue being empty/full.
// Attention, when use blocking pattern, invoke ProduceCompletely() to notify consumer
// thread stop waiting any data, or consumer will be the waiting state forever.
//

#ifndef __RING__QUEUE__SINGLE__MODEL__BOUND__H
#define __RING__QUEUE__SINGLE__MODEL__BOUND__H

#include "ring_queue_define.h"
#include "ring_queue_blocking_interface.h"
#include "byte_buffer_dynamic.h"
#include "byte_buffer_static.h"
#include "buffer_define.h"
#include "condition_variable.h"

namespace amz {

// This class use "ByteBufferStaticMalloc" as its ring queue.
class RingQueueSingleModelBound : public RingQueueBlockingInterface {
  // typedef
  typedef ByteBufferStaticMalloc StaticRingQueue;
  
 public:
  // In single thread, argument blocking must give "false".
  RingQueueSingleModelBound(uint32 ring_size = ring_queue_define::kDefaultRingQueueSize,
         bool blocking = false);
  virtual ~RingQueueSingleModelBound();

  virtual int GetType() { return ring_queue_define::RingQueueType_SingleBound; }

  // Use only for producer thread.
  virtual int Add(const char *element, uint32 size);

  // Use only for consumer thread.
  virtual int Remove(char *element, uint32 max_size);

  // When producer finish producing, this should be invoked
  virtual void ProduceCompletely();

  // Check all the producers produce completely.
  virtual bool CheckAllProducersComplete();

  // Debug print member.
  void LogPrint();

 private:
  // The ring queue.
  StaticRingQueue ring_;
  // size of ring queue.
  uint32 ring_size_;
  // The position to write the next data element.
  volatile uint32 write_pointer_;
  // The position to read from the ring queue.
  volatile uint32 read_pointer_;

  // Blocking pattern.
  bool blocking_;

  // Condition variable.
  ConditionVariable condition_not_empty_;
  ConditionVariable condition_not_full_;
  // mutex
  mutable Mutex mutex_not_empty_;
  mutable Mutex mutex_not_full_;

  bool produce_completely_;
};

}  // namespace amz

#endif  // __RING__QUEUE__SINGLE__MODEL__BOUNDLESS__H

